import re
import os
from errno import errorcode

import imageio
import pandas as pd
import os
import cv2
import random
import pandas as pd
from PIL import Image
import shutil
import json
model = dict()
class detectutils:

    def write_xml(mid_path, x_train, x_test):

        train_data_list = []
        # train写成xml文件
        # train_file_list供评估使用
        with open(mid_path + '/train.xml', 'w', encoding='gbk') as file:
            file.write("<dataset>\n")
            file.write("<images>\n")
            for string in x_train:
                file_path = "<image file= '%s'>\n" % (string[0])
                file.write(file_path)
                train_box_list = []
                for box_string in string[1]:
                    box = "<box top=\'%s\' left=\'%s\' width=\'%s\' height=\'%s\'/>\n" % (
                        box_string[0], box_string[1], box_string[2], box_string[3])
                    file.write(box)
                    right = int(box_string[1]) + int(box_string[2])
                    bottom = int(box_string[0]) + int(box_string[3])
                    train_box_list.append([box_string[1], box_string[0], right, bottom])
                file.write("</image>\n")
                train_data_list.append([string[0], train_box_list])
            file.write("</images>\n")
            file.write("</dataset>\n")

        test_data_list = []
        # test数据集写成路径和box的list
        for string in x_test:
            test_box_list = []
            for box_string in string[1]:
                right = int(box_string[1]) + int(box_string[2])
                bottom = int(box_string[0]) + int(box_string[3])
                test_box_list.append([box_string[1], box_string[0], right, bottom])
            test_data_list.append([string[0], test_box_list])

        return mid_path + '/train.xml', pd.DataFrame(train_data_list, columns=['image_path', 'box']), pd.DataFrame(
            test_data_list, columns=['image_path', 'box'])

    def shot_image_data(mid_path, x_train, x_test):
        ###路径不能存在中文名字，非则截图保存失败

        shot_image_path = mid_path + "/images_shot/"
        # 判断是否存在文件夹如果不存在则创建为文件夹
        folder = os.path.exists(shot_image_path)
        if not folder:
            os.makedirs(shot_image_path)  # makedirs 创建文件时如果路径不存在会创建这个路径

        x_train.extend(x_test)
        shot_image_list = []
        for data in x_train:
            img_path = data[0]
            basename = os.path.basename(img_path)
            for temp in data[1]:
                box = temp[0:4]
                lable = temp[4]
                box = list(map(int, box))
                img = cv2.imread(img_path)
                crop = img[box[0]:(box[0] + box[3]), box[1]:(box[1] + box[2])]

                # crop = img[27:45, 67:119]
                if os.path.isfile(shot_image_path + str(basename)):
                    a = str(int(random.uniform(1, 1000)))
                    cv2.imwrite(shot_image_path + a + str(basename), crop)
                    shot_image_list.append([shot_image_path + a + str(basename), lable])
                else:
                    cv2.imwrite(shot_image_path + str(basename), crop)
                    shot_image_list.append([shot_image_path + str(basename), lable])

        return pd.DataFrame(shot_image_list, columns=['file_path', 'lable'])

    def shot(img_path, box):
        basename = os.path.basename(img_path)
        box = list(map(int, box))
        img = cv2.imread(img_path)
        crop = img[box[1]:box[3], box[0]:box[2]]
        res = cv2.resize(img, (125, 125)).flatten()
        return res

    def detect_evaluate(data):
        total_box = 0
        false_detection = 0
        true_detection = 0

        y_true = dict()
        y_pred = dict()
        for index, row in data.iterrows():
            y_true[os.path.basename(row['image_path'])] = row['box']
            y_pred[os.path.basename(row['image_path'])] = row['box_predict']

        for key in y_true:
            true_list = []
            predict_box_list = []
            for box_true in y_true[key]:
                total_box += 1
                if key in y_pred.keys():
                    for box_predict in y_pred[key]:
                        if box_predict not in predict_box_list:
                            predict_box_list.append(box_predict)
                        ##计算覆盖率
                        x1, y1, x2, y2 = float(box_true[0]), float(box_true[1]), float(box_true[2]), float(box_true[3])
                        x1, x2 = min(x1, x2), max(x1, x2)
                        y1, y2 = min(y1, y2), max(y1, y2)
                        x3, y3, x4, y4 = float(box_predict[0]), float(box_predict[1]), float(box_predict[2]), float(
                            box_predict[3])
                        x3, x4 = min(x3, x4), max(x3, x4)
                        y3, y4 = min(y3, y4), max(y3, y4)
                        if (x2 <= x3 or x4 <= x1) and (y2 <= y3 or y4 <= y1):
                            continue
                        else:
                            lens = min(x2, x4) - max(x1, x3)
                            wide = min(y2, y4) - max(y1, y3)
                            coverage = (lens * wide) / ((x2 - x1) * (y2 - y1))
                            if coverage >= 0.70:
                                if box_true not in true_list:
                                    true_list.append(box_true)

            false_detection += len(predict_box_list) - len(true_list)
            true_detection += len(true_list)
            miss_detection = total_box - true_detection
        return miss_detection,false_detection,true_detection

    def transform_write_xml(mid_path, x_train, x_test):

        train_data_list = []
        # train写成xml文件
        # train_file_list供评估使用

        folder = os.path.exists(mid_path + '/train/annotations/')
        if not folder:
            os.makedirs(mid_path + '/train/annotations/')  # makedirs 创建文件时如果路径不存在会创建这个路径
        for string in x_train:
            basename = os.path.basename(string[0])
            with open(mid_path + '/train/annotations/' + os.path.splitext(basename)[0] + '.xml', 'w',
                      encoding='gbk') as file:
                file.write("<annotation>\n")
                file.write("<folder>images</folder>\n")
                file.write("<filename>%s</filename>\n" % (basename))
                abspath = os.path.abspath(string[0])
                file.write("<path>%s</path>\n" % (abspath))
                file.write("<size>\n")
                im = Image.open(string[0])  # 返回一个Image对象
                file.write("<width>%s</width>\n" % (im.size[0]))
                file.write("<height>%s</height>\n" % (im.size[1]))
                file.write("</size>\n")
                train_box_list = []
                for box_string in string[1]:
                    file.write("<object>\n")
                    file.write("<name>%s</name>\n"%(box_string[4]))
                    right = int(box_string[1]) + int(box_string[2])
                    bottom = int(box_string[0]) + int(box_string[3])
                    file.write("<bndbox>\n")
                    file.write("<xmin>%s</xmin>\n" % (int(box_string[1])))
                    file.write("<ymin>%s</ymin>\n" % (int(box_string[0])))
                    file.write("<xmax>%s</xmax>\n" % (right))
                    file.write("<ymax>%s</ymax>\n" % (bottom))
                    file.write("</bndbox>\n")
                    file.write("</object>\n")
                    train_box_list.append([box_string[1], box_string[0], right, bottom])
                file.write("</annotation>\n")
            train_data_list.append([string[0], train_box_list])

        test_data_list = []
        # test数据集写成路径和box的list
        folder = os.path.exists(mid_path + '/validation/annotations/')
        if not folder:
            os.makedirs(mid_path + '/validation/annotations/')  # makedirs 创建文件时如果路径不存在会创建这个路径
        for string in x_test:
            basename = os.path.basename(string[0])
            with open(mid_path + '/validation/annotations/' + os.path.splitext(basename)[0] + '.xml', 'w',
                      encoding='gbk') as file:
                file.write("<annotation>\n")
                file.write("<folder>images</folder>\n")
                file.write("<filename>%s</filename>\n" % (basename))
                abspath = os.path.abspath(string[0])
                folder = os.path.exists(mid_path + '/validation/images/')
                if not folder:
                    os.makedirs(mid_path + '/validation/images/')  # makedirs 创建文件时如果路径不存在会创建这个路径
                shutil.move(abspath, mid_path + '/validation/images/')
                abspath = mid_path + '/validation/images/' + basename
                file.write("<path>%s</path>\n" % (abspath))
                file.write("<size>\n")
                im = Image.open(abspath)  # 返回一个Image对象
                file.write("<width>%s</width>\n" % (im.size[0]))
                file.write("<height>%s</height>\n" % (im.size[1]))
                file.write("</size>\n")
                test_box_list = []
                for box_string in string[1]:
                    file.write("<object>\n")
                    file.write("<name>%s</name>\n"%(box_string[4]))
                    right = int(box_string[1]) + int(box_string[2])
                    bottom = int(box_string[0]) + int(box_string[3])
                    test_box_list.append([box_string[1], box_string[0], right, bottom])
                #         test_data_list.append([mid_path + '\\' +string[0],test_box_list])
                    file.write("<bndbox>\n")
                    file.write("<xmin>%s</xmin>\n" % (int(box_string[1])))
                    file.write("<ymin>%s</ymin>\n" % (int(box_string[0])))
                    file.write("<xmax>%s</xmax>\n" % (right))
                    file.write("<ymax>%s</ymax>\n" % (bottom))
                    file.write("</bndbox>\n")
                    file.write("</object>\n")
                file.write("</annotation>\n")
            test_data_list.append([abspath, test_box_list])

        return mid_path, pd.DataFrame(train_data_list, columns=['image_path', 'box']), pd.DataFrame(test_data_list,columns=['image_path','box'])


    def write_json(obj,json_path):
        '''
        写入/追加json文件
        :param obj:
        :return:
        '''

        def Merge(dict1, dict2):
            return (dict2.update(dict1))

        # 首先读取已有的json文件中的内容
        with open(json_path, 'rb') as f:
            load_dict = json.load(f)
            anchors = load_dict['anchors']
            labels = load_dict['labels']
            item_dict = {'anchors': anchors, 'labels': labels}
        dict2 = dict(dict(obj)['label'])
        # 读取已有内容完毕
        # 将新传入的dict对象追加至list中
        Merge(item_dict, dict2)
        # 将追加的内容与原有内容写回（覆盖）原文件
        with open(json_path, 'w', encoding='utf-8') as f2:
            jsObj = json.dumps(dict2, ensure_ascii=False)
            f2.write(jsObj)
